"""
    Usage:
            createxml [--help] [-h] [--inputDir=DIR] [-i DIR]
                      [--temporaryDir=DIR] [-t DIR]
                      [--outputDir=DIR] [-o DIR] [CSVFILE(s)]

        --inputDir      Directory from which to read input files.
        -i              Defaults to ./

        --temporaryDir  Directory in which to store intermediate files duing creation.
        -t              Defaults to ../tmp
        
        --outputDir     Directory used as delivery point to master system.
        -o              Defaults to ../net/xmlin/xmlrcv
        
        --help          Displays this help page.
        -h

    Author Anders Sodergrann, 05.07.2010.

"""
import os.path
import xml.dom.minidom
import sys
import getopt
import csv
import logging
import time
import platform
import shutil
import os

LOG_FILENAME = os.path.join( "..", "tmp", "CREATEXML.py." + time.strftime("%Y%m%d", time.localtime() ) + ".dbg" )
#LOG_LEVEL=logging.DEBUG
LOG_LEVEL=logging.INFO

CONVERT_FILE_NAMED_CSV_ONLY=True

TRANSACTION_COUNT_FILE = os.path.join( os.path.dirname( os.path.abspath( sys.argv[0] ) ), "inTransactionCounter.dat" )

CSV_FIELD_CREATEDATE   = 1
CSV_FIELD_EMPLOYEEID   = 3
CSV_FIELD_WORKDATE     = 4
CSV_FIELD_STARTTIME    = 5
CSV_FIELD_ENDTIME      = 6
CSV_FIELD_DAYTYPE      = 7
CSV_FIELD_EMPLOYEECAT  = 8
CSV_FIELD_EMPLOYEEDEPT = 9
CSV_FIELD_EMPLOYEEFORM = 10



def createNodeWithText( doc, nodeName, nodeText ):
    newNode = doc.createElement( nodeName )
    pText = doc.createTextNode( nodeText )
    newNode.appendChild( pText )
    return newNode


def createTimeFormat( inTime ):

    dateTimeSplit = str.split( inTime )

    if len( dateTimeSplit ) == 2 :

        dateString = dateTimeSplit[0]
        timeString = dateTimeSplit[1]

        secSplit = str.split( timeString, "." )
        partSecPresent = ( len( secSplit ) > 1 )
        timeSplit = str.split( secSplit[0], ":" )
        secondsPresent = ( len( timeSplit ) >= 3 )
        minutesPresent = ( len( timeSplit ) >= 2 )
        hoursPresent = ( len( timeSplit ) >= 1 )

        returnString = dateString + "T"
        if hoursPresent:
            returnString += timeSplit[0] + ":"
        if minutesPresent:
            returnString += timeSplit[1] + ":"
        else:
            returnString += "00:"
        if secondsPresent:
            returnString += timeSplit[2] + "."
        else:
            returnString += "00."
        if partSecPresent:
            returnString += secSplit[1]
        else:
            returnString += "0"
            
    else:
        returnString = inTime

    return returnString

# end createTimeFormat



def createWorkSchedule( csvRow ):
    
    doc = xml.dom.minidom.Document()
    workSchedule = doc.createElement( 'WorkSchedule' )
    workSchedule.appendChild( createNodeWithText( doc, 'WorkDate', csvRow[CSV_FIELD_WORKDATE] ) )
    workSchedule.appendChild( createNodeWithText( doc, 'StartTime', createTimeFormat( csvRow[CSV_FIELD_STARTTIME] ) ) )
    workSchedule.appendChild( createNodeWithText( doc, 'EndTime', createTimeFormat( csvRow[CSV_FIELD_ENDTIME] ) ) )
    workSchedule.appendChild( createNodeWithText( doc, 'DayType', csvRow[CSV_FIELD_DAYTYPE] ) )

    return workSchedule
# END createWorkSchedule


def createMasterDocument( csvRow, workScheduleArea, sequenceId ):

    doc = xml.dom.minidom.Document()
    
    astroEnvelope = doc.createElement( "Astro_Envelope" )
    astroEnvelope.setAttribute( "version", "0100" )
    astroEnvelope.setAttributeNS( "http://www.w3.org", "xsi:noNamespaceSchemaLocation", "../xsd/xsd/Doc/EmployeeWorkScheduleSync_0100.xsd" )
    astroEnvelope.setAttributeNS( "http://www.w3.org", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" )

    employeeWorkScheduleSync = doc.createElement( "EmployeeWorkScheduleSync" )
    employeeWorkScheduleSync.setAttribute( "version", "0100" )

    controlArea = doc.createElement( "ControlArea" )

    sender = doc.createElement( "Sender" )
    division = doc.createElement( "Division" )
    confirmation = createNodeWithText( doc, 'Confirmation', "0" )
    sender.appendChild( division )
    sender.appendChild( confirmation )
    #creationDateTime = createNodeWithText( doc, 'CreationDateTime', createTimeFormt( csvRow[CSV_FIELD_CREATEDATE] ) )
    creationDateTime = createNodeWithText( doc, 'CreationDateTime', csvRow[CSV_FIELD_CREATEDATE] )
    refId = doc.createElement( "RefId" )
    #idText = csvRow[2]
    #idText = time.strftime("%d%H%M%S", time.localtime() ) + str( sequenceId )
    idText = "%ld" % getNextTransactionNumberAndUpdate( TRANSACTION_COUNT_FILE )
    id = createNodeWithText( doc, 'Id', idText )
    refId.appendChild( id )

    controlArea.appendChild( sender )
    controlArea.appendChild( creationDateTime )
    controlArea.appendChild( refId )

    dataArea = doc.createElement( "DataArea" )
    employeeWorkSchedule = doc.createElement( "EmployeeWorkSchedule" )

    employeeId = createNodeWithText( doc, 'EmployeeId', csvRow[CSV_FIELD_EMPLOYEEID] )

    workScheduleEmploymentArea = doc.createElement( "WorkScheduleEmploymentArea" )
    employeeDepartment = createNodeWithText( doc, 'EmployeeDepartment', csvRow[CSV_FIELD_EMPLOYEEDEPT] )
    # Use field "Anstaellningsform" at Elgiganten
    #employeeCategory = createNodeWithText( doc, 'EmployeeCategory', csvRow[CSV_FIELD_EMPLOYEECAT] )
    
    # Only accept fields (1,2,3) otherwise ''
    categoryTestList = ['1','2','3']
    if csvRow[CSV_FIELD_EMPLOYEEFORM] in categoryTestList:
        stringEmployeeCategory = csvRow[CSV_FIELD_EMPLOYEEFORM]
    else:
        stringEmployeeCategory = " "
    employeeCategory = createNodeWithText( doc, 'EmployeeCategory', stringEmployeeCategory )
    employeeExternalReference = createNodeWithText( doc, 'EmployeeExternalReference', "N/A" )

    workScheduleEmploymentArea.appendChild( employeeDepartment )
    workScheduleEmploymentArea.appendChild( employeeCategory )
    workScheduleEmploymentArea.appendChild( employeeExternalReference )

    employeeWorkSchedule.appendChild( employeeId )
    employeeWorkSchedule.appendChild( workScheduleEmploymentArea )
    employeeWorkSchedule.appendChild( workScheduleArea )

    dataArea.appendChild( employeeWorkSchedule )

    employeeWorkScheduleSync.appendChild( controlArea )
    employeeWorkScheduleSync.appendChild( dataArea )

    astroEnvelope.appendChild( employeeWorkScheduleSync )
    doc.appendChild( astroEnvelope )

    return doc

#end createMasterDocument



def generateXMLout( doc, tempDir, outputDir, sequenceId ):

    #print doc.toprettyxml("    ", "\n", "UTF-8")
    #print xml.toxml("UTF-8")
    #filenamePart = "WSCHEDSYNC" + time.strftime("%Y%m%d%H%M%S%Z", time.localtime() ) + "Q" + str( sequenceId ) + ".xml"
    
    # Astro adaptation
    # 0        1         2
    # 1234567890123456789012345
    # WSC100706141129Qnnnnn.xml
    if sequenceId > 99999:
        sequenceId -= 99999 
    filenamePart = "WSC" + time.strftime("%y%m%d%H%M%S", time.localtime() ) + "Q" + str( sequenceId ) + ".xml"
    tempFilename = os.path.join( tempDir, filenamePart )
    outputFilename = os.path.join( outputDir, filenamePart )
    
    try:
        fp = open( tempFilename, "w")
    except IOError:
        logging.error( "Failed to create output XML in %s, aborting" %tempDir )
        sys.exit(1)

    doc.writexml(fp, indent="", addindent="", newl="", encoding="UTF-8")
    fp.close()

    try:
        shutil.move( tempFilename, outputFilename)
    except IOError:
        logging.error( "Failed to move XML file to output dir, aborting" )
        sys.exit(1)

# end generateXMLout


def copyOriginalFile( inputFile, inputDir ):

    ayOhError = False
    source = os.path.join( os.path.abspath(inputDir), inputFile )
    target = os.path.join( os.path.join( os.path.dirname(os.path.abspath(inputDir)), "log", inputFile ) )
    
    try:
        shutil.copy( source, target )
    except IOError:
        logging.error( "Failed to copy CSV file %s to log dir." %inputFile )
        logging.error( "    source [" + source + "] target [" + target + "]." )
        ayOhError = True
        pass

    copySucceeded = ( not ayOhError )

    return copySucceeded


def deleteOriginalFile( inputFile, inputDir ):

    ayOhError = False
    source = os.path.join( os.path.abspath(inputDir), inputFile )
    
    try:
        os.remove( source )
    except IOError:
        logging.error( "Failed to delete CSV file %s ." %inputFile )
        ayOhError = True
        pass

    deleteSucceeded = ( not ayOhError )

    return deleteSucceeded
    


def processCSVfile( inputFile, tempDir, inputDir, outputDir ):

    csvFileCopied = copyOriginalFile( inputFile, inputDir )
    
    if not csvFileCopied:
        return
    
    employeeId = ""
    oldEmployeeId = ""
    originalRow = ""
    firstRun = True
    ayOhError = False
    createdDocuments = 0
    doc = xml.dom.minidom.Document()
    workScheduleArea = doc.createElement( "WorkScheduleArea ")
    
    csvFile = os.path.join( inputDir, inputFile )

    try:
        reader = csv.reader( open( csvFile ), delimiter=';', quoting=csv.QUOTE_NONE )
    except IOError:
        logging.error('Failed to open %s, trying next.' %csvFile )
        ayOhError = True
        pass

    if ayOhError:
        return

    for row in reader:

        employeeId = row[CSV_FIELD_EMPLOYEEID]

        if oldEmployeeId != employeeId:
            if firstRun :
                firstRun = False
            else:
                # Generate new base doc
                generateXMLout( createMasterDocument( originalRow, workScheduleArea, createdDocuments ), tempDir, outputDir, createdDocuments )
                createdDocuments += 1

            workScheduleArea = doc.createElement( "WorkScheduleArea ")
            originalRow = row
            oldEmployeeId = employeeId

        workScheduleArea.appendChild( createWorkSchedule( row ) )

    # Create last document
    generateXMLout( createMasterDocument( originalRow, workScheduleArea, createdDocuments ), tempDir, outputDir, createdDocuments )
    createdDocuments += 1
    logging.info( "Generated " + str(createdDocuments) + " XML-files from " + csvFile + " into " + os.path.abspath(outputDir) + " ." )
    
    if csvFileCopied:
        deleteOriginalFile( inputFile, inputDir )
        

# end processCSVfile


def getNextTransactionNumberAndUpdate( transactionCountFile ):

    transactionNumber = 0
    returnValue = 0

    try:
        transactionCountFileExists = os.path.exists( transactionCountFile )
        
        if transactionCountFileExists :
            
            transCntHandle = open( transactionCountFile, 'r+' )
            nextCountString = transCntHandle.readline()
            settingSplit = str.split( nextCountString, "=" )

            if ( settingSplit[0] == "NextTransactionNumber" ) and ( len( settingSplit ) == 2 ) :
                transactionNumber = long( settingSplit[1] )
            transCntHandle.seek(0)

        else:

            transCntHandle = open( transactionCountFile, 'w' )

        returnValue = transactionNumber

        if transactionNumber > 999999998 :
            transactionNumber = 0
        else:
            transactionNumber += 1

        nextCountString = "NextTransactionNumber=%ld\n" % transactionNumber
        transCntHandle.write( nextCountString )
        transCntHandle.close()
        
    except IOError:
        logging.error( "Failed to r/w %s file. Aborting." %transactionCountFile )
        sys.exit(1)
        
    return returnValue



def main():    

    logging.basicConfig(filename=LOG_FILENAME,level=LOG_LEVEL)
    #logging.setFormatter( logging.Formatter("%(name)s : %(asctime)s : %(levelname)s : %(message)s") )

    timeString = time.strftime("%Y-%m-%d %H:%M:%S %Z", time.localtime() )
    logging.info('--- Startup at %s ---' %timeString )
    logging.info( "Executing on " + platform.system() )
    logging.debug( "Called using " + str( sys.argv[0:] ) )
    
    inputDir = os.path.join( "..", "net", "csvin", "convert" )
    tempDir = os.path.join( "..", "tmp" )
    outputDir = os.path.join( "..", "net", "xmlin", "xmlrcv" )
    #inputFile = os.path.join( inputDir, "EmployeeWorkScheduleSync_20100629.csv" )
    inputFile = os.path.join( inputDir, "EmployeeWorkScheduleSync_201006xx.csv" )
    
    # parse command line options
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hi:t:o:", ["help","inputDir=","temporaryDir=","outputDir="])
    except getopt.error, msg:
        print msg
        print "for help use --help"
        sys.exit(2)

    # process options
    for o, a in opts:
        if o in ("-h", "--help"):
            print __doc__
            sys.exit(0)
        if o in ("-i", "--inputDir"):
            inputDir = a
        if o in ("-t", "--temporaryDir"):
            tempDir = a
        if o in ("-o", "--outputDir"):
            outputDir = a

    logging.info( "Script called is " + sys.argv[0] )
    logging.info( "Using inputDir=" + inputDir )
    logging.info( "Using tempDir=" + tempDir )
    logging.info( "Using outputDir=" + outputDir )

    # process arguments
    if len( args ) == 0 :
        if os.path.exists( os.path.abspath( inputDir ) ) :
            dirList = os.listdir( os.path.abspath( inputDir ) )
        else:
            dirList = os.listdir( os.path.dirname( os.path.abspath( sys.argv[0] ) ) )
            
        for fileInDir in dirList:
            #print fileInDir
            #if os.path.isfile( fileInDir ) :
            #print fileInDir
            if CONVERT_FILE_NAMED_CSV_ONLY :
                fileParts = fileInDir.split(".")
                if (fileParts[ len( fileParts ) - 1 ]).lower() == "csv" :
                    args.append( fileInDir )
            else:
                args.append( fileInDir )
                    
    for arg in args:
        processCSVfile( arg, tempDir, inputDir, outputDir )

    timeString = time.strftime("%Y-%m-%d %H:%M:%S %Z", time.localtime() )
    logging.info('--- Shutdown at %s ---' %timeString )

#if __name__ == "__main__":
main()


